package statistics

import (
	"context"
	"sort"
	"strconv"
	"strings"

	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/dao"
	"sale-admin/internal/models"

	"github.com/golang-module/carbon/v2"
	"gorm.io/gorm"
)

type DrawService struct{}

// Draw 用户画像
/*
	Type
	1 时
	2 日
	3 周
	4 月
	5 年
	6 按年龄段
*/
func (ds DrawService) Draw(ctx context.Context, db *gorm.DB, merchantID, goodsName string, operateType int, salesID string,
	shopIDList []string, Type int, startTime, endTime, areas1, areas2, areas3 string, page, limit int,
) (data interface{}, err error) {
	if Type != 0 && Type <= 5 { // 按日期  --- 首页和核心看板使用的
		switch Type {
		case 1:
			fallthrough
		case 2:
			fallthrough
		case 3: // 周时间范围转换
			startTime = carbon.Parse(startTime).StartOfDay().ToDateTimeString()
			endTime = carbon.Parse(endTime).EndOfDay().ToDateTimeString()
		case 4: // 月时间范围转换
			startTime = carbon.Parse(startTime).StartOfMonth().ToDateTimeString()
			endTime = carbon.Parse(endTime).EndOfMonth().ToDateTimeString()
		case 5:
			startTime = carbon.Parse(startTime).StartOfYear().ToDateTimeString()
			endTime = carbon.Parse(endTime).EndOfYear().ToDateTimeString()
		}
		data, err = ds.getAgeCount(ctx, db, merchantID, operateType, salesID, shopIDList, startTime, endTime, areas1, areas2, areas3)
	} else { // 按年龄段 -- 展开和日期列表使用的
		drawData, count, totalCount, err := ds.getDrawData(ctx, db, merchantID, operateType, salesID, shopIDList, Type,
			startTime, endTime, areas1, areas2, areas3, page, limit)
		if err == nil {
			data = map[string]interface{}{
				"data":        drawData,
				"count":       count,
				"total_count": totalCount,
			}
		}
	}
	return
}

func (ds DrawService) getAgeCount(ctx context.Context, db *gorm.DB, merchantID string, operateType int, salesID string,
	shopIDList []string, startTime, endTime, areas1, areas2, areas3 string) (data []struct {
	Age   int `json:"age"`
	Sex0  int `json:"sex0"`
	Sex1  int `json:"sex1"`
	Sex_1 int `json:"sex-1"`
}, err error,
) {
	tx := db.Model(models.MaPhysicalInfo{})
	if merchantID == "1" && salesID == "" && ((len(shopIDList) == 1 && shopIDList[0] == "1") || len(shopIDList) == 0) { // 系统用户 && 不查salesID && 不查商户 【首页客户画像】
	} else { // 其他情况
		merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
		if err1 != nil {
			return
		}
		robotList, _, _ := dao.Robot{}.RobotList(ctx, db, strings.Join(merchantIDs, ","), "", "", salesID, areas1, areas2, areas3, "")
		SalesIDList := []string{}
		for _, v := range robotList {
			SalesIDList = append(SalesIDList, v.SalesID)
		}
		salesID = strings.Join(SalesIDList, ",")
		tx.Where("sales_id in (?)", strings.Split(salesID, ","))
	}
	if startTime != "" && endTime != "" {
		tx.Where("add_time BETWEEN ? AND ?", startTime, endTime)
	}
	if operateType != 0 { // 操作类型 1点击 2创单 3支付 4 点击空白（非商品）
		tx.Where("type = ?", operateType)
	}
	Res := []struct {
		AgeRange int    `json:"age_range"`
		Sex      string `json:"sex"`
		Count    int    `json:"count"`
	}{}

	tx.Select("age_range,sex,count(id) as count").
		Group("age_range,sex").
		Order("age_range").
		Find(&Res)

	AgeSexCountMap := make(map[string]int) //{age}_Sex_{sex}   sex : 0 1 -1
	for _, v := range Res {
		switch v.AgeRange {
		case 4:
			AgeSexCountMap["4_Sex_"+v.Sex] = v.Count
		case 7:
			AgeSexCountMap["7_Sex_"+v.Sex] = v.Count
		case 11:
			AgeSexCountMap["11_Sex_"+v.Sex] = v.Count
		case 19:
			AgeSexCountMap["19_Sex_"+v.Sex] = v.Count
		case 29:
			AgeSexCountMap["29_Sex_"+v.Sex] = v.Count
		case 39:
			AgeSexCountMap["39_Sex_"+v.Sex] = v.Count
		case 49:
			AgeSexCountMap["49_Sex_"+v.Sex] = v.Count
		case 50:
			AgeSexCountMap["50_Sex_"+v.Sex] = v.Count
		default:
			AgeSexCountMap["404_Sex_"+v.Sex] = v.Count
		}
	}
	ReturnData := []struct {
		Age   int `json:"age"`
		Sex0  int `json:"sex0"`
		Sex1  int `json:"sex1"`
		Sex_1 int `json:"sex-1"`
	}{
		{Age: 4, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 7, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 11, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 19, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 29, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 39, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 49, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 50, Sex0: 0, Sex1: 0, Sex_1: 0},
		{Age: 404, Sex0: 0, Sex1: 0, Sex_1: 0},
	}
	for k, v := range ReturnData {
		ageString := strconv.Itoa(v.Age)
		if _, ok := AgeSexCountMap[ageString+"_Sex_0"]; ok {
			ReturnData[k].Sex0 = AgeSexCountMap[ageString+"_Sex_0"]
		}
		if _, ok := AgeSexCountMap[ageString+"_Sex_1"]; ok {
			ReturnData[k].Sex1 = AgeSexCountMap[ageString+"_Sex_1"]
		}
		if _, ok := AgeSexCountMap[ageString+"_Sex_-1"]; ok {
			ReturnData[k].Sex_1 = AgeSexCountMap[ageString+"_Sex_-1"]
		}
	}
	return ReturnData, nil
}

type DrawDataTotalCount struct {
	ScreenCount      int64 `json:"screen_count"`
	ScreenCountMan   int64 `json:"screen_count_man"`
	ScreenCountWoman int64 `json:"screen_count_woman"`
	ScreenCountNot   int64 `json:"screen_count_not"`
	GoodsCount       int64 `json:"goods_count"`
	GoodsCountMan    int64 `json:"goods_count_man"`
	GoodsCountWoman  int64 `json:"goods_count_woman"`
	GoodsCountNot    int64 `json:"goods_count_not"`
	CreateCount      int64 `json:"create_count"`
	CreateCountMan   int64 `json:"create_count_man"`
	CreateCountWoman int64 `json:"create_count_woman"`
	CreateCountNot   int64 `json:"create_count_not"`
	PayCount         int64 `json:"pay_count"`
	PayCountMan      int64 `json:"pay_count_man"`
	PayCountWoman    int64 `json:"pay_count_woman"`
	PayCountNot      int64 `json:"pay_count_not"`
}

type DrawDataList struct {
	Date    string `json:"date"`
	SalesID string `json:"sales_id"`
	Type    int    `json:"type"`
	Msg     string `json:"msg"`
	Sex     int    `json:"sex"`
	Age     int    `json:"age"`
	Count   int64  `json:"count"`
}

func (ds DrawService) getDrawData(ctx context.Context, db *gorm.DB, merchantID string, operateType int, salesID string, shopIDList []string, Type int, startTime, endTime, areas1, areas2, areas3 string, page, limit int) (data []struct {
	DrawDataTotalCount
	DateGroup string `json:"date_group"`
	AgeGroup  string `json:"age_group"`
}, count int64, totalCount DrawDataTotalCount, err error,
) {
	tx := db.Model(models.MaPhysicalInfo{})
	if merchantID == "1" && salesID == "" && ((len(shopIDList) == 1 && shopIDList[0] == "1") || len(shopIDList) == 0) { // 系统用户 && 不查salesID && 不查商户 【首页客户画像】
	} else { // 其他情况
		merchantIDs, err1 := common.Order{}.GetMerchantChildren(ctx, merchantID, shopIDList)
		if err1 != nil {
			return
		}
		robotList, _, _ := dao.Robot{}.RobotList(ctx, db, strings.Join(merchantIDs, ","), "", "", salesID, areas1, areas2, areas3, "")
		SalesIDList := []string{}
		for _, v := range robotList {
			SalesIDList = append(SalesIDList, v.SalesID)
		}
		salesID = strings.Join(SalesIDList, ",")
		tx.Where("sales_id in (?)", strings.Split(salesID, ","))
	}
	if startTime != "" && endTime != "" {
		tx.Where("add_time BETWEEN ? AND ?", startTime, endTime+" 23:59:59")
	}
	if operateType != 0 { // 操作类型 1点击 2创单 3支付 4 点击空白（非商品）
		tx.Where("type = ?", operateType)
	}

	var Count int64
	tx.WithContext(ctx).Group("date_format(add_time, '%Y-%m-%d')").Count(&Count)
	DrawDataRes := []DrawDataList{}
	tx.WithContext(ctx).Select("date_format(add_time, '%Y-%m-%d') AS date, sales_id, type, msg, sex, age, count(id) as count").
		Group("date, type, sex, sales_id").
		Order("date desc").
		Find(&DrawDataRes)

	DataGroupMap := make(map[string][]DrawDataList)
	// 年龄分组
	totalCount = DrawDataTotalCount{}
	if startTime != "" && endTime != "" && startTime == endTime && Type == 6 {
		for _, v := range DrawDataRes {
			if v.Age >= 1 && v.Age <= 4 {
				DataGroupMap["4"] = append(DataGroupMap["4"], v)
			} else if v.Age >= 5 && v.Age <= 7 {
				DataGroupMap["7"] = append(DataGroupMap["7"], v)
			} else if v.Age >= 8 && v.Age <= 11 {
				DataGroupMap["11"] = append(DataGroupMap["11"], v)
			} else if v.Age >= 12 && v.Age <= 19 {
				DataGroupMap["19"] = append(DataGroupMap["19"], v)
			} else if v.Age >= 20 && v.Age <= 29 {
				DataGroupMap["29"] = append(DataGroupMap["29"], v)
			} else if v.Age >= 30 && v.Age <= 39 {
				DataGroupMap["39"] = append(DataGroupMap["39"], v)
			} else if v.Age >= 40 && v.Age <= 49 {
				DataGroupMap["49"] = append(DataGroupMap["49"], v)
			} else if v.Age >= 50 {
				DataGroupMap["50"] = append(DataGroupMap["50"], v)
			} else {
				DataGroupMap["404"] = append(DataGroupMap["404"], v)
			}
		}
	} else {
		// 日期分组
		for _, v := range DrawDataRes {
			DataGroupMap[v.Date] = append(DataGroupMap[v.Date], v)
		}
	}
	ResultData := []struct {
		DrawDataTotalCount
		DateGroup string `json:"date_group"`
		AgeGroup  string `json:"age_group"`
	}{}
	for groupKey, groupValue := range DataGroupMap {
		item := struct {
			DrawDataTotalCount
			DateGroup string `json:"date_group"`
			AgeGroup  string `json:"age_group"`
		}{
			DateGroup: groupKey,
			AgeGroup:  groupKey,
		}
		for _, v := range groupValue {
			if v.Type == 1 { // 1.点击商品
				totalCount.GoodsCount += v.Count
				item.GoodsCount += v.Count
				if v.Sex == 1 {
					totalCount.GoodsCountMan += v.Count
					item.GoodsCountMan += v.Count
				} else if v.Sex == 0 {
					totalCount.GoodsCountWoman += v.Count
					item.GoodsCountWoman += v.Count
				} else if v.Sex == -1 {
					totalCount.GoodsCountNot += v.Count
					item.GoodsCountNot += v.Count
				}
			} else if v.Type == 2 { // 2.点击创单
				totalCount.CreateCount += v.Count
				item.CreateCount += v.Count

				if v.Sex == 1 {
					totalCount.CreateCountMan += v.Count
					item.CreateCountMan += v.Count
				} else if v.Sex == 0 {
					totalCount.CreateCountWoman += v.Count
					item.CreateCountWoman += v.Count
				} else if v.Sex == -1 {
					totalCount.CreateCountNot += v.Count
					item.CreateCountNot += v.Count
				}
			} else if v.Type == 3 { // 3.点击支付
				totalCount.PayCount += v.Count
				item.PayCount += v.Count
				if v.Sex == 1 {
					totalCount.PayCountMan += v.Count
					item.PayCountMan += v.Count
				} else if v.Sex == 0 {
					totalCount.PayCountWoman += v.Count
					item.PayCountWoman += v.Count
				} else if v.Sex == -1 {
					totalCount.PayCountNot += v.Count
					item.PayCountNot += v.Count
				}
			} else if v.Type == 4 { // 4.点击空白
				totalCount.ScreenCount += v.Count
				item.ScreenCount += v.Count
				if v.Sex == 1 {
					totalCount.ScreenCountMan += v.Count
					item.ScreenCountMan += v.Count
				} else if v.Sex == 0 {
					totalCount.ScreenCountWoman += v.Count
					item.ScreenCountWoman += v.Count
				} else if v.Sex == -1 {
					totalCount.ScreenCountNot += v.Count
					item.ScreenCountNot += v.Count
				}
			}
			if v.Date == groupKey { // 时间分组
				item.AgeGroup = ""
			} else { // 年龄分组
				item.DateGroup = ""
			}
		}
		ResultData = append(ResultData, item)
	}
	sort.Slice(ResultData, func(i, j int) bool {
		return ResultData[i].DateGroup > ResultData[j].DateGroup
	})

	start, end := common.SlicePage(page, limit, len(ResultData))
	ResultData = ResultData[start:end]
	return ResultData, Count, totalCount, nil
}
